home *** CD-ROM | disk | FTP | other *** search
/ Floppyshop 2 / Floppyshop - 2.zip / Floppyshop - 2.iso / art&graf.ix / art-3871 / mdl10 / xdl.c < prev    next >
C/C++ Source or Header  |  1993-06-04  |  16KB  |  572 lines

  1. /*
  2.  * xdl 2.0 -- display a DL animation in an X-window.
  3.  *
  4.  *
  5.  * Author:
  6.  *      Jonas Yngvesson <jonas-y@isy.liu.se>
  7.  *
  8.  * Derived from dltogl.c by:
  9.  *    George Phillips <phillips@cs.ubc.ca>
  10.  *
  11.  * Support for user defined animation speed:
  12.  *      Per Beremark <per.beremark@telelogic.se>
  13.  */
  14.  
  15. #include <stdio.h>
  16. #include <signal.h>
  17. #ifdef __convex__
  18. #include <stdlib.h>
  19. #else
  20. #include <malloc.h>
  21. #endif
  22. #include <sys/types.h>
  23. #include <sys/time.h>
  24.  
  25. #include <X11/Xos.h>
  26. #include <X11/Xlib.h>
  27. #include <X11/Xutil.h>
  28.  
  29. #define isneg16(x)    ((x) & 0x8000)
  30. #define neg16(x)    ((~(x) + 1) & 0x7fff)
  31.  
  32.  
  33. typedef struct {
  34.     int   version;
  35.     int   format;
  36.     int   images_per_screen;
  37.     char  title[21];
  38.     char  author[21];
  39.     int   num_screen;
  40.     int   num_command;
  41. } DL_info;
  42.  
  43.  
  44. Display *x_display;
  45. Window   x_window;
  46. int      x_depth;
  47. u_long   pixels[256];
  48. Pixmap  *pixmap;
  49. XImage  *x_image;
  50. GC       gc_clear;
  51.  
  52.  
  53. /*
  54.  * Initialize the colormap. I use a private one for PseudoColor,
  55.  * I was too tired to fiddle with allocating shared colors.
  56.  */
  57. static void
  58. colormap_setup(fp, version)
  59.     FILE *fp;
  60.     int   version;
  61. {
  62.     Colormap cmap;
  63.     XColor   color;
  64.     u_char   pal[768];
  65.     int      i;
  66.  
  67.     /* Is this the border colour? */
  68.     if (version == 2)
  69.         for (i = 0; i < 3; i++)
  70.             fgetc(fp);
  71.     else
  72.         fgetc(fp);
  73.     
  74.     /*
  75.      * Here comes the colormap.
  76.      */
  77.     fread(pal, 1, 768, fp);
  78.     
  79.     /*
  80.      * Set up for grayscale conversion on a monochrome display.
  81.      */
  82.     if (x_depth == 1) {
  83.         for (i = 0; i < 256; i++) {
  84.             pixels[i] = (u_long)((pal[3 * i] << 2) * 0.30 
  85.                                  + (pal[3 * i + 1] << 2) * 0.59
  86.                                  + (pal[3 * i + 2] << 2) * 0.11);
  87.         }
  88.         return;
  89.     }
  90.         
  91.     /*
  92.      * Allocate colors on color displays.
  93.      */
  94.     if (x_depth == 8) {
  95.         cmap = XCreateColormap(x_display, x_window, 
  96.                    DefaultVisual(x_display, 
  97.                          DefaultScreen(x_display)),
  98.                                AllocNone);
  99.     } else {
  100.         cmap = DefaultColormap(x_display, DefaultScreen(x_display));
  101.     }
  102.  
  103.     for (i = 0; i < 256; i++) {
  104.         /*
  105.          * X wants 16 bit color specs and VGA uses 6 ==> shift 10 bits.
  106.          */
  107.         color.red   = pal[3 * i    ] << 10;
  108.         color.green = pal[3 * i + 1] << 10;
  109.         color.blue  = pal[3 * i + 2] << 10;
  110.         XAllocColor(x_display, cmap, &color);
  111.         pixels[i] = color.pixel;
  112.     }
  113.  
  114.     if (x_depth == 8) {        
  115.         XSetWindowColormap(x_display, x_window, cmap);
  116.     }
  117. }
  118.  
  119.  
  120.  
  121. /*
  122.  * Wait for a key to be pressed. In "dltogl" it was
  123.  * printed as a "waitkey" command to GL with a numeric
  124.  * argument. I don't know any GL commands so I don't know
  125.  * if the argument was a request to wait for a specific key
  126.  * or a timeout for how long to wait or anything else.
  127.  * I just wait forever for any key to be pressed.
  128.  */
  129. static void
  130. wait_for_key()
  131. {
  132.     XEvent event;
  133.     Bool   done;
  134.  
  135.     done = False;
  136.     while (!done) {
  137.         XNextEvent(x_display, &event);
  138.         if (event.type == KeyPress) {
  139.             done = True;
  140.         }
  141.     }
  142. }
  143.  
  144.  
  145.  
  146. /*
  147.  * Set up the X window.
  148.  */
  149. static void
  150. x_window_setup(title, author)
  151.     char *title;
  152.     char *author;
  153. {
  154.     XSetWindowAttributes  win_attr;    /* storage for "window attributes" */
  155.     XSizeHints            hints;       /* storage for "window hints" */
  156.     XGCValues             gcval;
  157.     int                   screen;
  158.     char                  label[256];
  159.  
  160.     /*
  161.      * Open the display.
  162.      */
  163.     if (NULL == (x_display = XOpenDisplay(NULL))) {
  164.         fputs("Can't open display.\n", stderr);
  165.         exit(1);
  166.     }
  167.  
  168.     /*
  169.      * Create the window.
  170.      */
  171.     screen = DefaultScreen(x_display);
  172.     x_depth = DefaultDepth(x_display, DefaultScreen(x_display));
  173.     x_window = XCreateSimpleWindow(x_display, DefaultRootWindow(x_display),  
  174.                                    100, 100, 320, 200, 0, 
  175.                                    BlackPixel(x_display, screen), 
  176.                                    BlackPixel(x_display, screen));
  177.  
  178.     /* 
  179.      * set up "window hints" so that we won't be allowed to
  180.      * resize the window while it's running 
  181.      */
  182.     sprintf(label, "%s %s %s", title, (author[0] ? "by" : ""), author);
  183.     hints.flags = PSize | PMinSize | PMaxSize;
  184.     hints.width = hints.min_width = hints.max_width = 320;
  185.     hints.height = hints.min_height = hints.max_height = 200;
  186.     XSetStandardProperties(x_display, x_window, label, title, 
  187.                            None, NULL, 0, &hints);
  188.  
  189.     /*
  190.      * Tell the server which events we want to recieve.
  191.      * Enable backing store so we don't have to worry
  192.      * about exposes (yes I know, backing store is not
  193.      * guaranteed, but it works for me, hah).
  194.      */
  195.     win_attr.event_mask = KeyPressMask;
  196.     win_attr.backing_store = Always;
  197.     XChangeWindowAttributes(x_display, x_window, 
  198.                             CWEventMask | CWBackingStore, &win_attr);
  199.  
  200.     gcval.foreground = BlackPixel(x_display, screen);
  201.     gc_clear = XCreateGC(x_display, x_window, GCForeground, &gcval);
  202.  
  203.     XMapWindow(x_display, x_window);
  204.     XSync(x_display, False);
  205. }
  206.  
  207.  
  208. static void die(s)char*s;{fprintf(stderr,"%s\n",s);exit(1);}
  209.  
  210.  
  211. void
  212. main(argc, argv)
  213.     int        argc;
  214.     char*    argv[];
  215. {
  216.     DL_info           dlinfo;
  217.     struct itimerval  timer;
  218.     struct timeval    timeout;
  219.     char             *filename;
  220.     FILE             *fp;
  221.     u_char           *image_data;
  222.     char             *err1, *err2, *tmp;
  223.     short             alpha[256], beta[256], gamma[256], delta[256];
  224.     short             gray, err;
  225.     u_long            black, white;
  226.     int               dx, dy;
  227.     int               width, height;
  228.     int              *cmd;
  229.     int               labelpos, label;
  230.     int               cmdnum;
  231.     int               frame_freq;
  232.     int               fps = 25;
  233.     int               zoomflag = 0;
  234.     int               errflg = 0;
  235.     int               i, j;
  236.     extern char      *optarg;
  237.     extern int        optind;
  238.  
  239.  
  240.     /*
  241.      * Lets see what option we got from the user.
  242.      */
  243.     while ((i = getopt(argc, argv, "zhr:")) != -1) {
  244.     switch (i) {
  245.       case 'z':
  246.         zoomflag = 1;
  247.           break;
  248.  
  249.       case 'h':
  250.         errflg++;
  251.         break;
  252.  
  253.       case 'r':
  254.         fps = atoi(optarg);
  255.         if (fps < 2) {
  256.             printf("Minimum value is 2 frames per second.\n");
  257.             fps = 2;
  258.         }
  259.         break;
  260.  
  261.       case '?':
  262.       default:
  263.         errflg++;
  264.     }
  265.     }
  266.     if (errflg) { 
  267.         fputs("usage: xdl [-z] [-h] [-r frames/second] [file.dl]\n", stderr);
  268.     exit (2);
  269.     }
  270.     
  271.     if (argv[optind] == NULL) {
  272.         fp = stdin;
  273.         filename = "stdin";
  274.     } else if (NULL == (fp = fopen(argv[optind], "r"))) {        
  275.         fprintf(stderr, "xdl: can't open %s\n", argv[1]);
  276.         exit(1);
  277.     } else {
  278.         filename = argv[optind];
  279.     }
  280.  
  281.  
  282.     /*
  283.      * Check the version number...
  284.      */
  285.     if (1 != (dlinfo.version = fgetc(fp)) && 2 != dlinfo.version) {
  286.         fprintf(stderr, "xdl: This file is in an unknown format.\n");
  287.         fprintf(stderr, "     I can only do .DL version 1 and 2.\n", 
  288.                 dlinfo.version);
  289.         exit(1);
  290.     }
  291.     
  292.  
  293.     /*
  294.      * ...and the format.
  295.      */
  296.     if (dlinfo.version == 1)
  297.         dlinfo.format = 1;
  298.     else
  299.         dlinfo.format = fgetc(fp);
  300.     
  301.     switch (dlinfo.format) {
  302.       case 0: /* large */
  303.         dx = dy = 0;
  304.         width = 320;
  305.         height = 200;
  306.         dlinfo.images_per_screen = 1;
  307.         zoomflag = 0;
  308.         break;
  309.       case 1: /* medium */
  310.         if (zoomflag) {
  311.             dx = dy = 0;
  312.             width = 320;
  313.             height = 200;
  314.         } else {
  315.             dx = 80;
  316.             dy = 50;
  317.             width = 160;
  318.             height = 100;
  319.         }
  320.         dlinfo.images_per_screen = 4;
  321.         break;
  322.       default:
  323.         die("xdl: only large and medium formats are handled");
  324.         break;
  325.     }
  326.     
  327.  
  328.     /*
  329.      * Get title and author (if any).
  330.      */
  331.     dlinfo.title[20] = dlinfo.author[20] = 0;
  332.     for (i = 0; i < 20; i++) {
  333.         dlinfo.title[i] = fgetc(fp) ^ 255;
  334.         if ((u_char)dlinfo.title[i] == 255) {
  335.             dlinfo.title[i] = 0;
  336.         }
  337.     }
  338.     for (i = 0; i < 20; i++) {
  339.         if (dlinfo.version == 2) {
  340.             dlinfo.author[i] = fgetc(fp) ^ 255;
  341.             if ((u_char)dlinfo.author[i] == 255) {
  342.                 dlinfo.author[i] = 0;
  343.             }
  344.         } else {
  345.             dlinfo.author[i] = 0;
  346.         }
  347.     }
  348.     
  349.  
  350.     /*
  351.      * Read number of screens and commands.
  352.      */
  353.     dlinfo.num_screen = fgetc(fp);
  354.     dlinfo.num_command = fgetc(fp);
  355.     
  356.  
  357.     /*
  358.      * Display what we know so far.
  359.      */
  360.     printf("%s is a %s sized version %d .DL file.\n", filename, 
  361.            (dlinfo.format == 0 ? "large" : "medium"), 
  362.            dlinfo.version);
  363.     printf("It containes %d images in a %d frame loop.\n",
  364.            dlinfo.num_screen * dlinfo.images_per_screen, dlinfo.num_command);
  365.     if (dlinfo.format == 1 && zoomflag) {
  366.         puts("Zooming images to 320x200.");
  367.     }
  368.     printf("Displaying animation at %d frames per second.\n",fps);
  369.     
  370.  
  371.     /*
  372.      * Kick X into action.
  373.      */
  374.     x_window_setup(dlinfo.title, dlinfo.author);
  375.     colormap_setup(fp, dlinfo.version);
  376.     
  377.  
  378.     /*
  379.      * Allocate memory for the commands, the image data
  380.      * and all the pixmaps.
  381.      */
  382.     if (!(cmd = (int *)malloc(dlinfo.num_command * sizeof(int))))
  383.         die("xdl: out of memory");
  384.     if (NULL == (image_data = (u_char *)malloc(320 * 200))) {
  385.         die("xdl: not enough memory.");
  386.     }
  387.     if (NULL == (pixmap = (Pixmap *)malloc(dlinfo.num_screen 
  388.                                            * dlinfo.images_per_screen
  389.                                            * sizeof(Pixmap)))) {
  390.         die("xdl: not enough memory.");
  391.     }
  392.     
  393.  
  394.     /*
  395.      * Set up for error distribution
  396.      * on monochrome displays.
  397.      */
  398.     if (x_depth == 1) {
  399.         for (i = 0; i < 256; i++) {
  400.             alpha[i] = ((i - 128) * 7) / 16;
  401.             beta[i] = ((i - 128) * 3) / 16;
  402.             gamma[i] = ((i - 128) * 5) / 16;
  403.             delta[i] = ((i - 128) * 1) / 16;
  404.         }
  405.         err1 = malloc(322);
  406.         err2 = malloc(322);
  407.         black = BlackPixel(x_display, DefaultScreen(x_display));
  408.         white = WhitePixel(x_display, DefaultScreen(x_display));
  409.     }
  410.  
  411.  
  412.     /*
  413.      * Build the pixmaps for the animation.
  414.      */
  415.     printf("Building pixmaps, wait..."); fflush(stdout);
  416.     for (j = 0; j < dlinfo.num_screen; j++) {
  417.         u_char    *src;
  418.         int      row;
  419.         int      col;
  420.  
  421.  
  422.         /*
  423.          * Read one screen of data.
  424.          */
  425.         fread(image_data, 1, 320 * 200, fp);
  426.  
  427.  
  428.         /*
  429.          * Each screen can hold several images.
  430.          */
  431.         for (i = 0; i < dlinfo.images_per_screen; i++) {
  432.             if (x_depth == 1) {
  433.                 bzero(err1, 322);
  434.             }
  435.  
  436.  
  437.             /*
  438.              * Get a pixmap for the image.
  439.              */
  440.             pixmap[j * (dlinfo.format * 3 + 1) + i] 
  441.                 = XCreatePixmap(x_display, x_window, 320, 200, x_depth);
  442.             XFillRectangle(x_display, pixmap[j * (dlinfo.format * 3 + 1) + i],
  443.                            gc_clear, 0, 0, 320, 200);
  444.             x_image = XGetImage(x_display, 
  445.                                 pixmap[j * (dlinfo.format * 3 + 1) + i], 
  446.                                 dx, dy, width, height, AllPlanes, ZPixmap);
  447.  
  448.  
  449.             /*
  450.              * Get a pointer to the beginning of this image.
  451.              * Put the pixels in the x-image and perform
  452.              * error distribution if needed. We do zooming
  453.              * by reading the same data several times, together
  454.              * with error distribution this gives us some smoothing
  455.              * for free! :-)
  456.              */
  457.             src = image_data + (i % 2) * 160 + (i / 2) * 100 * 320;
  458.             for (row = 0; row < height; row++) {
  459.                 if (x_depth == 1) {
  460.                     bzero(err2, 322);
  461.                 }
  462.                 for (col = 0; col < width; col++) {
  463.  
  464.                     if (x_depth == 1) {                                
  465.                         gray = pixels[*src] + err1[col + 1];
  466.                         if (gray < 128) {
  467.                             err = gray;
  468.                             XPutPixel(x_image, col, row, black);
  469.                         } else {
  470.                             err = gray - 256;
  471.                             XPutPixel(x_image, col, row, white);
  472.                         }
  473.                         err1[col + 2] += alpha[err + 128];
  474.                         err2[col    ] += beta[err + 128];
  475.                         err2[col + 1] += gamma[err + 128];
  476.                         err2[col + 2] += delta[err + 128];
  477.  
  478.                     } else {
  479.                         XPutPixel(x_image, col, row, pixels[*src]);
  480.                     }
  481.                     src += (zoomflag) ? (col & 1) : 1;
  482.                 }
  483.  
  484.                 if (x_depth == 1) {
  485.                     tmp = err1;
  486.                     err1 = err2;
  487.                     err2 = tmp;
  488.                 }
  489.  
  490.                 if (dlinfo.format) {
  491.                     if (zoomflag) {
  492.                         src += (row & 1) ? 160 : -160;
  493.                     } else {
  494.                         src += 160;
  495.                     }
  496.                 }
  497.             }
  498.  
  499.  
  500.             /*
  501.              * Put the image in the pixmap.
  502.              */
  503.             XPutImage(x_display, pixmap[j * (dlinfo.format * 3 + 1) + i], 
  504.                       DefaultGC(x_display, DefaultScreen(x_display)), 
  505.                       x_image, 0, 0, dx, dy, width, height);
  506.         }
  507.     }
  508.     printf("done.\n");
  509.  
  510.  
  511.     /*
  512.      * Read the commands.
  513.      */
  514.     for (i = 0; i < dlinfo.num_command; i++) {
  515.         if (dlinfo.version == 2) {
  516.             j = fgetc(fp);
  517.             j += fgetc(fp) << 8;
  518.             cmd[i] = j;
  519.         } else {
  520.             j = fgetc(fp);
  521.             cmd[i] = (j % 10) - 1 + ((j / 10) - 1) * 4;
  522.         }
  523.     }
  524.     
  525.     labelpos = 0;
  526.     if (isneg16(cmd[dlinfo.num_command - 1])) {
  527.         labelpos = (neg16(cmd[dlinfo.num_command - 1]) 
  528.                     + 1); /* Correct? Why add 1 ?? */
  529.         dlinfo.num_command--;    /* ignore that last command */
  530.     }
  531.     
  532.  
  533.     /*
  534.      * Now for the animation. I use setitimer() and getitimer()
  535.      * to try to keep 25 frames/sec. (Not that all DL-files are
  536.      * adjusted to that but it seem natural)
  537.      * However, as Per Beremark noted, most files seem to be tuned
  538.      * for 10 - 12 frames/sec so it is possible to change the
  539.      * speed with the -r switch.
  540.      */
  541.     signal(SIGALRM, SIG_IGN);
  542.     frame_freq = 1000000/fps;
  543.     i = 0;
  544.     cmdnum = 0;
  545.     label = -1;
  546.     while (1) {
  547.         for (; i < dlinfo.num_command; i++, cmdnum++) {
  548.             if (cmdnum == labelpos && label == -1) {
  549.                 label = i;
  550.             }
  551.             if (isneg16(cmd[i])) {
  552.                 i++;              /* Skip argument to waitkey, see above */
  553.                 wait_for_key();
  554.             } else {
  555.                 timer.it_interval.tv_sec = 0;
  556.                 timer.it_interval.tv_usec = frame_freq;
  557.                 timer.it_value.tv_sec = 0;
  558.                 timer.it_value.tv_usec = frame_freq;
  559.                 setitimer(ITIMER_REAL, &timer, NULL);
  560.                 XCopyArea(x_display, pixmap[cmd[i]], x_window, 
  561.                           DefaultGC(x_display, DefaultScreen(x_display)), 
  562.                           0, 0, 320, 200, 0, 0);
  563.                 XSync(x_display, False);
  564.                 getitimer(ITIMER_REAL, &timer);
  565.                 timeout = timer.it_value;
  566.                 select(0, NULL, NULL, NULL, &timeout);
  567.             }
  568.         }
  569.         i = cmdnum = label;
  570.     }
  571. }
  572.